import type { Router, RouteLocationNormalized } from "vue-router"
import { useAppStoreWithOut } from "/@/store/modules/app"
import { useUserStoreWithOut } from "/@/store/modules/user"
import { useTransitionSetting } from "/@/hooks/setting/useTransitionSetting"
import { AxiosCanceler } from "/@/utils/http/axios/axiosCancel"
import { Modal, notification } from "ant-design-vue"
import { warn } from "/@/utils/log"
import { unref } from "vue"
import { setRouteChange } from "/@/logics/mitt/routeChange"
import { createPermissionGuard } from "./permissionGuard"
import { createWorkspaceGuard } from "./workspaceGuard"
import { createStateGuard } from "./stateGuard"
import nProgress from "nprogress"
import projectSetting from "/@/settings/projectSetting"
import { createParamMenuGuard } from "./paramMenuGuard"
import { LAST_ROUTE_PATH } from "/@/enums/cacheEnum"
import { setCacheByDynKey } from "/@/utils/cache"
import * as authCache from "/@/utils/cache/module/auth"
import { UserInfo } from "/@/api/sys/model/userModel"
import { PageEnum } from "/@/enums/pageEnum"
import { useAppStore } from "/@/store/modules/app"
import { useMessage } from "/@/hooks/web/useMessage"

// const userStore = useUserStore()
// Don't change the order of creation
export function setupRouterGuard(router: Router) {
  createPageGuard(router)
  createPageLoadingGuard(router)
  createHttpGuard(router)
  createScrollGuard(router)
  createMessageGuard(router)
  createProgressGuard(router)
  createPermissionGuard(router)
  createWorkspaceGuard(router)
  createParamMenuGuard(router) // must after createPermissionGuard (menu has been built.)
  createStateGuard(router)
}

/**
 * Hooks for handling page state
 */
function createPageGuard(router: Router) {
  const loadedPageMap = new Map<string, boolean>()

  router.beforeEach(async (to) => {
    // 判断页面数据是否保存
    const useApp = useAppStore()
    const pageDataSaveFlag = useApp.getPageDataSaveFlag
    if (!pageDataSaveFlag) {
      const { createConfirm } = useMessage()
      createConfirm({
        title: "确定离开此页面？",
        content: useApp.getPageUnsaveTipContent,
        iconType: "warning",
        onOk: () => {
          useApp.setPageDataSaveFlag(true)
          router.push(to)
        }
      })
      return false
    }

    // The page has already been loaded, it will be faster to open it again, you don’t need to do loading and other processing
    to.meta.loaded = !!loadedPageMap.get(to.path)
    // Notify routing changes
    setRouteChange(to)
    if (to.path !== "/login" && to.path !== PageEnum.BASE_HOME && to.path !== `/${PageEnum.BASE_HOME}/index`) {
      const userInfo = authCache.getUserInfo()
      if (!userInfo) {
        return true
      }
      const key = LAST_ROUTE_PATH + userInfo.currentTenantId + userInfo.currentAppId + userInfo.currentServiceCode
      setCacheByDynKey(key, to.path)
    }
    return true
  })

  router.afterEach((from, to) => {
    loadedPageMap.set(to.path, true)
  })
}

// Used to handle page loading status
function createPageLoadingGuard(router: Router) {
  const userStore = useUserStoreWithOut()
  const appStore = useAppStoreWithOut()
  const { getOpenPageLoading } = useTransitionSetting()
  router.beforeEach(async (to) => {
    if (!userStore.getToken) {
      return true
    }
    if (to.meta.loaded) {
      return true
    }

    if (unref(getOpenPageLoading)) {
      appStore.setPageLoadingAction(true)
      return true
    }

    return true
  })
  router.afterEach(async () => {
    if (unref(getOpenPageLoading)) {
      // TODO Looking for a better way
      // The timer simulates the loading time to prevent flashing too fast,
      setTimeout(() => {
        appStore.setPageLoading(false)
      }, 220)
    }
    return true
  })
}

/**
 * The interface used to close the current page to complete the request when the route is switched
 * @param router
 */
function createHttpGuard(router: Router) {
  const { removeAllHttpPending } = projectSetting
  let axiosCanceler: Nullable<AxiosCanceler>
  if (removeAllHttpPending) {
    axiosCanceler = new AxiosCanceler()
  }
  router.beforeEach(async () => {
    // Switching the route will delete the previous request
    axiosCanceler?.removeAllPending()
    return true
  })
}

// Routing switch back to the top
function createScrollGuard(router: Router) {
  const isHash = (href: string) => {
    return /^#/.test(href)
  }

  const body = document.body

  router.afterEach(async (to) => {
    // scroll top
    isHash((to as RouteLocationNormalized & { href: string })?.href) && body.scrollTo(0, 0)
    return true
  })
}

/**
 * Used to close the message instance when the route is switched
 * @param router
 */
export function createMessageGuard(router: Router) {
  const { closeMessageOnSwitch } = projectSetting

  router.beforeEach(async () => {
    try {
      if (closeMessageOnSwitch) {
        Modal.destroyAll()
        notification.destroy()
      }
    } catch (error) {
      warn("message guard error:" + error)
    }
    return true
  })
}

export function createProgressGuard(router: Router) {
  const { getOpenNProgress } = useTransitionSetting()
  router.beforeEach(async (to) => {
    if (to.meta.loaded) {
      return true
    }
    unref(getOpenNProgress) && nProgress.start()
    return true
  })

  router.afterEach(async () => {
    unref(getOpenNProgress) && nProgress.done()
    return true
  })
}
